package projet_v1.basics;

import static org.junit.Assert.*;

import java.util.ArrayList;

import org.junit.Before;
import org.junit.Test;

import projet_v1.Actor;
import projet_v1.Breed;
import projet_v1.Human;
import projet_v1.Vampire;
import projet_v1.Zombie;
import projet_v1.items.ammo.Ammo;
import projet_v1.items.ammo.CategoryAmmo;
import projet_v1.items.help.FirstAidKit;
import projet_v1.items.help.Food;
import projet_v1.items.weapons.Shotgun;
import projet_v1.simulation.Field;
import projet_v1.simulation.Location;

/**
 * Test class of human class
 * 
 * @author Antoine Lavail
 * 
 */
public class TestHuman {

    private Human human1;
    private Human human2;

    /**
     * @throws java.lang.Exception
     */
    @Before
    public void setUp() throws Exception {
        human1 = new Human(100);
        human2 = new Human(100, new Field(30, 30), new Location(25, 25));
    }

    /**
     * Test method for
     * {@link projet_v1.Human#encounterCharacter(projet_v1.Character)}.
     */
    @Test(expected = NullPointerException.class)
    public void testEncounterCharacter() {

        Vampire v = new Vampire(250, new Field(30, 30), new Location(24, 25));
        Shotgun s = new Shotgun();
        human2.putIntoBag(s);
        assertTrue(s.isFull());
        human2.encounterCharacter(v);
        if (v.getHealthPoints() < 250)
            assertEquals(Breed.HUMAN, v.getLastAttackedBy());
        assertFalse(s.isFull());

        // NullPointerException
        human2.encounterCharacter(null);
    }

    /**
     * Test method for {@link projet_v1.Human#endOfTurn()}.
     */
    @Test
    public void testEndOfTurn() {
        assertEquals(0, human1.getTurnsSinceLastMeal());
        human1.endOfTurn();
        assertEquals(1, human1.getTurnsSinceLastMeal());
        human1.setTurnsSinceLastMeal(3);
        human1.endOfTurn();
        assertEquals(4, human1.getTurnsSinceLastMeal());
        assertEquals(98, human1.getHealthPoints());
    }

    /**
     * Test method for
     * {@link projet_v1.Human#act(projet_v1.simulation.Field, projet_v1.simulation.Field, java.util.List)}
     * .
     */
    @Test(expected = NullPointerException.class)
    public void testAct() {
        
        human2.reduceHealthPoints(30);
        assertEquals(70, human2.getHealthPoints());
        
        human2.setTurnsSinceLastMeal(2);
        
        Field currentField = new Field(30,30);
        Field updatedField = new Field(30,30);
        currentField.placeItem(new Shotgun(), new Location(25,25));
        currentField.placeItem(new Ammo(CategoryAmmo.GAUGE), new Location(25,25));
        currentField.placeItem(new FirstAidKit(), new Location(25,25));
        currentField.placeItem(new Food(), new Location(25,25));
        
        Zombie z = new Zombie(50, new Field(30,30), new Location(24,25));
        currentField.place(human2, new Location(25,25));
        updatedField.place(z, new Location(24,25));
        
        human2.act(currentField, updatedField, new ArrayList<Actor>());
        
        assertEquals(1, human2.getBag().size());
        assertEquals(90, human2.getHealthPoints());
        
        assertEquals(0, human2.getTurnsSinceLastMeal());
        if (z.getHealthPoints() < 50)
            assertEquals(Breed.HUMAN, z.getLastAttackedBy());

        // NullPointerException's
        human2.act(null, new Field(20,20), new ArrayList<Actor>());
        human2.act(new Field(20,20), null, new ArrayList<Actor>());
    }

    /**
     * Test method for {@link projet_v1.Human#Human(int)}.
     */
    @Test
    public void testHumanInt() {
        Human h = new Human(70);
        assertFalse(h.getHasBeenBitten());
        assertEquals(0, h.getTurnsSinceLastMeal());
    }

    /**
     * Test method for
     * {@link projet_v1.Human#Human(int, projet_v1.simulation.Field, projet_v1.simulation.Location)}
     * .
     */
    @Test
    public void testHumanIntFieldLocation() {
        Human h = new Human(50, new Field(20, 30), new Location(10, 5));
        assertEquals(2, h.getSpeed());
    }

    /**
     * Test method for {@link projet_v1.Human#setHasBeenBitten(boolean)}.
     */
    @Test
    public void testSetHasBeenBitten() {
        assertFalse(human2.getHasBeenBitten());
        human2.setHasBeenBitten(true);
        assertTrue(human2.getHasBeenBitten());
    }

    /**
     * Test method for {@link projet_v1.Human#setTurnsSinceLastMeal(int)}.
     */
    @Test
    public void testSetTurnsSinceLastMeal() {
        assertEquals(0, human1.getTurnsSinceLastMeal());
        human1.setTurnsSinceLastMeal(6);
        assertEquals(6, human1.getTurnsSinceLastMeal());
    }

    /**
     * Test method for {@link projet_v1.Human#turnIntoVampire()}.
     */
    @Test
    public void testTurnIntoVampire() {
        Vampire v = human2.turnIntoVampire();
        assertEquals(human2.getHealthPoints(), v.getHealthPoints());
        assertEquals(human2.getLocation(), v.getLocation());
        assertTrue(v.getIsThirsty());
    }

    /**
     * Test method for {@link projet_v1.Human#turnIntoZombie()}.
     */
    @Test
    public void testTurnIntoZombie() {
        Zombie z = human2.turnIntoZombie();
        assertEquals(Zombie.HP_ZOMBIES, z.getHealthPoints());
        assertEquals(human2.getLocation(), z.getLocation());
    }

    /**
     * Test method for {@link projet_v1.Human#putIntoBag(projet_v1.Item)}.
     */
    @Test(expected = NullPointerException.class)
    public void testPutIntoBag() {

        // Declaration of a weapon, whom inherits item. For example : a shotgun.
        Shotgun s = new Shotgun();
        human2.putIntoBag(s);
        assertEquals(1, human2.getBag().size());
        assertEquals(s, human2.getBag().get(0));

        // NullPointerException
        human2.putIntoBag(null);
    }

    /**
     * Test method for {@link projet_v1.Human#incrementAge()}.
     */
    @Test
    public void testIncrementAge() {
        assertTrue(human1.isAlive());
        for (int i = 0; i < 200; i++)
            human1.incrementAge();
        assertFalse(human1.isAlive());
    }

    /**
     * Test method for {@link projet_v1.Human#setDead()}.
     */
    @Test
    public void testSetDead() {
        assertTrue(human1.isAlive());
        human1.setDead();
        assertEquals(0, human1.getHealthPoints());
        assertEquals(null, human1.getLocation());
    }

}
